package com.alex.space.commons.date.expression;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Alex
 *         Created by Alex on 2017/12/21.
 */
public abstract class DateExpression {

    String dateFormat = "yyyy-MM-dd";

    protected boolean match(String expression) {
        Pattern pattern = Pattern.compile(getRegEx());
        Matcher matcher = pattern.matcher(expression);
        boolean rs = matcher.matches();
        return rs;
    }

    protected DateModel express(String expression) {
        DateModel result = new DateModel();
        if (!match(expression)) {
            return result;
        }

        String[] strs = expression.split(getModel().getSplit());

        Date date = new Date();
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
            date = sdf.parse(strs[0]);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        int dateSpan = Integer.parseInt(strs[1].substring(0, strs[1].length() - 1));
        DateUnit dateUnit = DateUnit.parse(strs[1].substring(strs[1].length() - 1));

        Date end = generateBaseDate(date, dateSpan, dateUnit);
        result.setEnd(end);

        Calendar c = Calendar.getInstance();
        c.setTime(end);

        switch (dateUnit) {
            case YEAR:
                c.add(Calendar.YEAR, dateSpan * -1);
                break;
            case MONTH:
                c.add(Calendar.MONTH, dateSpan * -1);
                break;
            case DAY:
                c.add(Calendar.DATE, dateSpan * -1);
                break;
            case QUARTER:
                c.add(Calendar.MONTH, dateSpan * -3);
                break;
            case WEEK:
                c.add(Calendar.DATE, dateSpan * -7);
                break;
            default:
                break;
        }

        c.add(Calendar.DATE, 1);
        result.setStart(c.getTime());

        return result;
    }

    protected abstract String getRegEx();

    protected abstract ExpressionModel getModel();

    protected Date generateBaseDate(Date original, int dateSpan, DateUnit dateUnit) {
        return original;
    }

    enum ExpressionModel {
        Absolute("/"), Relative("\\|");

        private String split;

        ExpressionModel(String split) {
            this.split = split;
        }

        public String getSplit() {
            return split;
        }
    }

    enum DateUnit {
        YEAR("y"), MONTH("m"), DAY("d"), QUARTER("q"), WEEK("w");

        private String unit;

        DateUnit(String unit) {
            this.unit = unit;
        }

        public String getUnit() {
            return unit;
        }

        public static DateUnit parse(String unit) {
            if (unit.equalsIgnoreCase("y")) {
                return DateUnit.YEAR;
            } else if (unit.equalsIgnoreCase("m")) {
                return DateUnit.MONTH;
            } else if (unit.equalsIgnoreCase("d")) {
                return DateUnit.DAY;
            } else if (unit.equalsIgnoreCase("q")) {
                return DateUnit.QUARTER;
            } else if (unit.equalsIgnoreCase("w")) {
                return DateUnit.WEEK;
            }
            return DateUnit.YEAR;
        }
    }

}

